﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace PimImporter
{
    internal class CsvReader : IDisposable
    {
        private const char separator = ';';
        private const string quote = "\"";
        private string pathFile;
        private StreamReader reader = null;
        internal bool EndOfStream { get; private set; }
        private int colsNumber = -1;
        private bool firstLineHeader;

        public CsvReader(string pathFile, bool firstLineHeader)
        {
            this.pathFile = pathFile;
            reader = File.OpenText(pathFile);
            this.firstLineHeader = firstLineHeader;
        }

        public void Dispose()
        {
            if (reader != null)
            {
                reader.Dispose();
            }
        }

        internal string[] ReadRecord()
        {
            if (!reader.EndOfStream)
            {
                string line = reader.ReadLine();
                string[] cols = line.Split(separator);
                if (colsNumber == -1)
                {
                    colsNumber = cols.Length;
                }
                if (cols.Length != colsNumber)
                {
                    throw new MalformedDataException(line);
                }
                for (int i = 0; i < cols.Length; i++)
                {
                    cols[i] = TrimQuote(cols[i], i);
                }
                EndOfStream = reader.EndOfStream;
                return cols;
            }
            else
            {
                return null;
            }
        }

        private string TrimQuote(string quoted, int colsNum)
        {
            if (string.IsNullOrEmpty(quoted))
                return quoted;
            if ((quoted.StartsWith(quote) && !quoted.EndsWith(quote)) || (!quoted.StartsWith(quote) && quoted.EndsWith(quote)))
                throw new MalformedDataException(quoted);
            if (quoted.StartsWith(quote))
                quoted = quoted.Substring(1, quoted.Length - 1);
            if (quoted.EndsWith(quote))
                quoted = quoted.Substring(0, quoted.Length - 1);
            return quoted;
        }

        internal List<string> GetHeaders()
        {
            string[] headers = ReadRecord();
            if (headers == null)
            {
                throw new Exception("Error with mapping file. Please reinstall program");
            }
            List<string> tmp = new List<string>();
            foreach (var h in headers)
            {
                if (h != "")
                {
                    tmp.Add(h);
                }
            }
            return tmp;
        }

        internal int GetColumnsNumber()
        {
            int n = -1;
            bool first = true;
            while (!reader.EndOfStream)
            {
                int tmp = ReadRecord().Length;
                if (first)
                {
                    n = tmp;
                    first = false;
                }
                if (n != tmp)
                {
                    throw new Exception("Internal error. Please send me your file");
                }
                n = tmp;
            }
            reader.Close();
            reader = File.OpenText(pathFile);
            return n;
        }

        internal List<int> TestColumns(List<int> columnsNotMapped)
        {
            List<int> lista = new List<int>();
            while (!reader.EndOfStream)
            {
                var tmp = ReadRecord();
                foreach (var c in columnsNotMapped)
                {
                    if (tmp[c] != "")
                    {
                        if (!lista.Contains(c))
                        {
                            lista.Add(c);
                        }
                    }
                }
            }
            reader.Close();
            reader = File.OpenText(pathFile);
            if (firstLineHeader)
            {
                ReadRecord();
            }
            return lista;
        }

        internal int GetRecordsLen()
        {
            int num = 0;
            while (!reader.EndOfStream)
            {
                ReadRecord();
                num++;
            }
            reader.Close();
            reader = File.OpenText(pathFile);
            if (firstLineHeader)
            {
                ReadRecord();
            }
            return num;
        }
    }
}
